/*
* 文件：FFmpeg.cs
* 作者：王阳
* 时间：2019-5-20
* 描述：
*/
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;

namespace UnityX
{
    public class FFmpeg : IDisposable
    {
        private string binaryPath = null;
        private Thread thread = null;
        private Process process = null;
        private bool disposedValue = false;
        private StringBuilder outputBuilder = new StringBuilder();

        public string output => outputBuilder.ToString();
        public bool isRunning => thread != null;

        public FFmpeg(string command)
        {
#if UNITY_EDITOR
            string[] guids = UnityEditor.AssetDatabase.FindAssets("ffmpeg");
            foreach (string guid in guids)
            {
                string path = UnityEditor.AssetDatabase.GUIDToAssetPath(guid);
                if (Path.GetFileName(path) == "ffmpeg.exe")
                {
                    binaryPath = Path.GetFullPath(path);
                    break;
                }
            }
#else
            //binaryPath = Directory.GetCurrentDirectory() + "/FFmpeg/ffmpeg.exe";
            binaryPath = UnityEngine.Application.dataPath + "/FFmpeg/ffmpeg.exe";
#endif
            this.binaryPath = Path.GetFullPath(binaryPath);
            if (!File.Exists(this.binaryPath))
            {
                throw new InvalidOperationException("FFmpeg执行文件不存在：" + binaryPath);
            }
            BootThread(command);
        }
        public FFmpeg(string binaryPath, string command)
        {
            this.binaryPath = Path.GetFullPath(binaryPath);
            if (!File.Exists(this.binaryPath))
            {
                throw new InvalidOperationException("FFmpeg执行文件不存在：" + binaryPath);
            }
            BootThread(command);
        }
        /// <summary>
        /// 结束、停止FFmpeg.exe执行或录制
        /// </summary>
        public void Stop()
        {
            if (thread == null) return;
            if (process == null) return;

            process.StandardInput.WriteLine("q");//在这个进程的控制台中模拟输入q,用于暂停录制
        }
        private void BootThread(string command)
        {
            outputBuilder.Clear();
            thread = new Thread(BootProcess);
            thread.Start(command);
        }
        private void BootProcess(object c)
        {
            string command = c as string;
            try
            {
                ProcessStartInfo startInfo = new ProcessStartInfo();
                startInfo.WorkingDirectory = Directory.GetCurrentDirectory();
                startInfo.RedirectStandardInput = true;//这句一定需要，用于模拟该进程控制台的输入
                startInfo.RedirectStandardOutput = true;
                startInfo.RedirectStandardError = true;
                startInfo.UseShellExecute = false;
                startInfo.CreateNoWindow = true;
                startInfo.FileName = binaryPath;
                startInfo.Arguments = command;

                process = new Process();
                process.StartInfo = startInfo;
                process.OutputDataReceived += OutputDataReceived;
                process.ErrorDataReceived += ErrorDataReceived;

                process.Start();

                process.BeginOutputReadLine();
                process.BeginErrorReadLine();

                process.WaitForExit();

                process.Close();
                process.Dispose();
            }
            catch (Exception e)
            {
                UnityEngine.Debug.LogException(e);
            }
            process = null;
            thread = null;
        }
        private void OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            outputBuilder.AppendLine(e.Data);
        }
        private void ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (e.Data.Contains("Error opening input file video=screen-capture-recorder"))
            {
                Log.Error("录制视频环境未安装，请运行\"" + Path.GetDirectoryName(binaryPath) + "\\以管理员运行我安装.bat\"文件安装");
            }
            outputBuilder.AppendLine(e.Data);
        }
        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    // TODO: 释放托管状态(托管对象)
                }
                Stop();
                // TODO: 释放未托管的资源(未托管的对象)并重写终结器
                // TODO: 将大型字段设置为 null
                disposedValue = true;
            }
        }
        // TODO: 仅当“Dispose(bool disposing)”拥有用于释放未托管资源的代码时才替代终结器
        ~FFmpeg()
        {
            // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
            Dispose(disposing: false);
        }
        public void Dispose()
        {
            // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
            Dispose(disposing: true);
            GC.SuppressFinalize(this);
        }
    }
}